package it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyStackPanel;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.DeferredCommand;

import java.util.Vector;

import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyListeners.FClickListener;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyListeners.FClickListenerHandler;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyResizableCell.XY;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyVerticalTable.VerticalTableListener;


abstract public class FStackPanel extends Composite
{
    AbsolutePanel mainPanel;



    Vector<Widget> items = new Vector<Widget>();
    Vector<Widget> contents = new Vector<Widget>();

    Widget openedItem = null;
    Widget openedItemContent = null;

    StackPanelListenerCollection listenerCollection=new StackPanelListenerCollection();

    boolean block=false;

    int width, height;
    int headerHeight = 20;

    boolean animationEnabled=false;


    public FStackPanel() {

        initGui();

    }

    private void initGui() {
        mainPanel = new AbsolutePanel();
        initWidget(mainPanel);
    }

    public void addItem(final Widget item, final Widget content) {

        if(block)
         return;
     
        content.setPixelSize(0,0);
        items.add(item);
        contents.add(content);
        mainPanel.add(item);
        mainPanel.add(content);

        FClickListener.setClickEvent(item.getElement(), new FClickListenerHandler() {
            public void onClick() {
                openItemWithAnim(items.indexOf(item));
            }
        });



        updateUi();

    }

    public void insertItem(int beforeIndex, final Widget item, final Widget content) {


        if(block)
         return;

        if (beforeIndex < 0 || beforeIndex > items.size())
            throw new IndexOutOfBoundsException();

        items.insertElementAt(item, beforeIndex);
        contents.insertElementAt(content, beforeIndex);
        mainPanel.add(item);
        mainPanel.add(content);

        FClickListener.setClickEvent(item.getElement(), new FClickListenerHandler() {
            public void onClick() {
              openItemWithAnim(items.indexOf(item));
            }
        });

        updateUi();

    }

    public void removeItem(int index) {


        if(block)
         return;

        if (index < 0 || index > items.size())
            throw new IndexOutOfBoundsException();

        items.get(index).removeFromParent();
        contents.get(index).removeFromParent();

        items.remove(index);
        contents.remove(index);

        openedItem = null;
        openedItemContent = null;


        updateUi();
    }

    public int getItemCount() {
        return items.size();
    }

    public Widget getItem(int index)
    {

         if (index < 0 || index > items.size())
            throw new IndexOutOfBoundsException();
          return items.get(index);
    }

    public Widget getContent(int index)
    {
        if (index < 0 || index > items.size())
            throw new IndexOutOfBoundsException();
          return contents.get(index);
    }

    public void openItemWithAnim(int index) {
        if (index < 0 || index > items.size())
            throw new IndexOutOfBoundsException();



       if(openedItem!=null)
        if(index==items.indexOf(openedItem))
         return; 

       if(block)
         return;

        block=true; 



        openedItem = items.get(index);
        openedItemContent = contents.get(index);

        
        updateUiWithAnimation(index);

        

    }
   public  void openItem(int index) {
        if (index < 0 || index > items.size())
            throw new IndexOutOfBoundsException();

       if(openedItem!=null)
               if(index==items.indexOf(openedItem))
                return;
       


        openedItem = items.get(index);
        openedItemContent = contents.get(index);


        updateUi();
        listenerCollection.fireOnTabOpen(index);


    }



    protected void updateUi() {

        int nextPos = 0;
        int contentHeght = height - (headerHeight * items.size());


        for (int i=0;i<items.size();i++) {


            Widget item=items.get(i);
            if (item != openedItem) {


                mainPanel.setWidgetPosition(item, 0, nextPos);
                item.setPixelSize(width, headerHeight);

                  mainPanel.add(contents.get(i), 0, nextPos + headerHeight);
                contents.get(i).setPixelSize(width, contentHeght);

                nextPos += headerHeight;

            } else {
                mainPanel.setWidgetPosition(item, 0, nextPos);
                item.setPixelSize(width, headerHeight);
                                                                                                              

                mainPanel.add(contents.get(i), 0, nextPos + headerHeight);
                contents.get(i).setPixelSize(width, contentHeght);

                nextPos += headerHeight + contentHeght;

          }

        }

        for (int i = 0; i < contents.size() - 1; i++)
        {



           contents.get(i).setPixelSize(width, mainPanel.getWidgetTop(items.get(i + 1)) - mainPanel.getWidgetTop(items.get(i)) - headerHeight);
        }
            mainPanel.setWidgetPosition(contents.get(contents.size() - 1), 0, mainPanel.getWidgetTop(items.get(contents.size() - 1)) + headerHeight);



    }

    private void updateUiWithAnimation(int index) {



        int nextPos = 0;
        int contentHeght = height - (headerHeight * items.size());

        Vector<XY> widgetsSizes = new Vector<XY>();
        Vector<XY> widgetsPositions = new Vector<XY>();
        Vector<Widget> widgets = new Vector<Widget>();

        for (Widget item : items) {

            widgets.add(item);

            if (item != openedItem) {

                widgetsSizes.add(new XY(width, headerHeight));
                widgetsPositions.add(new XY(0, nextPos));

                nextPos += headerHeight;

            } else {

                widgetsSizes.add(new XY(width, headerHeight));
                widgetsPositions.add(new XY(0, nextPos));


                nextPos += headerHeight + contentHeght;

            }

        }


        animateWidgets(widgets, widgetsSizes, widgetsPositions,index);

    }

    private void animateWidgets(final Vector<Widget> widgets, final Vector<XY> widgetsSizes, final Vector<XY> widgetsPositions,final int index) {



        Timer timer = new Timer() {
            double step = 0;

            public void run() {
                if (step >= 100) {

                    for (int i = 0; i < widgets.size(); i++) {

                        Widget w = widgets.get(i);
                        int newLeft = (int) widgetsPositions.get(i).x;
                        int newTop = (int) widgetsPositions.get(i).y;
                        int newW = (int) widgetsSizes.get(i).x;
                        int newH = (int) widgetsSizes.get(i).y;
                        mainPanel.setWidgetPosition(w, newLeft, newTop);
                        w.setPixelSize(newW, newH);


                    }

                    for (int i = 0; i < contents.size() - 1; i++) {

                        mainPanel.setWidgetPosition(contents.get(i), 0, mainPanel.getWidgetTop(items.get(i)) + headerHeight);

                       contents.get(i).setPixelSize(width, mainPanel.getWidgetTop(items.get(i + 1)) - mainPanel.getWidgetTop(items.get(i)) - headerHeight);
                    }
                   // mainPanel.setWidgetPosition(contents.get(contents.size() - 1), 0, mainPanel.getWidgetTop(items.get(contents.size() - 1)) + headerHeight);
                   // contents.get(contents.size() - 1).setPixelSize(width, height - mainPanel.getWidgetTop(items.get(items.size() - 1)) - headerHeight);

                    cancel();
                    block=false;
                    animFinished();
                    listenerCollection.fireOnTabOpen(index);
                    return;
                }

                for (int i = 0; i < widgets.size(); i++) {

                    Widget w = widgets.get(i);


                    int oldLeft = mainPanel.getWidgetLeft(w);
                    int oldTop = mainPanel.getWidgetTop(w);
                    int oldW = w.getOffsetWidth();
                    int oldH = w.getOffsetHeight();


                    int newLeft = (int) widgetsPositions.get(i).x;
                    int newTop = (int) widgetsPositions.get(i).y;
                    int newW = (int) widgetsSizes.get(i).x;
                    int newH = (int) widgetsSizes.get(i).y;

                    mainPanel.setWidgetPosition(w, (int) (oldLeft + (newLeft - oldLeft) * step / 100), (int) ((oldTop + (newTop - oldTop) * step / 100)));
                    w.setPixelSize((int) (oldW + (newW - oldW) * step / 100), (int) ((oldH + (newH - oldH) * step / 100)));


                }

                for (int i = 0; i < contents.size() - 1; i++) {

                    mainPanel.setWidgetPosition(contents.get(i), 0, mainPanel.getWidgetTop(items.get(i)) + headerHeight);

                    contents.get(i).setPixelSize(width, mainPanel.getWidgetTop(items.get(i + 1)) - mainPanel.getWidgetTop(items.get(i)) - headerHeight);

                }
                mainPanel.setWidgetPosition(contents.get(contents.size() - 1), 0, mainPanel.getWidgetTop(items.get(contents.size() - 1)) + headerHeight);
                contents.get(contents.size() - 1).setPixelSize(width, height - mainPanel.getWidgetTop(items.get(items.size() - 1)) - headerHeight);


                step += 15;
                schedule(50);

            }
        };
        animStarted();
        timer.run();
        timer.schedule(50);
    }

    public void setHeaderHeight(int height) {

        if(block)
         return;

        headerHeight = height;
        updateUi();
    }

    public void setPixelSize(int w, int h) {


        if(block)
         return;
        
        super.setPixelSize(w, h);

        width = w;
        height = h;

        updateUi();

    }

    public void addStackPanelListener(StackPanelListener listener)
    {
       listenerCollection.add(listener);
    }

    public int getOpenItemIndex()
    {
        return items.indexOf(openedItem);
    }


    abstract public void animStarted();
    abstract public void animFinished();

}
